#pragma once
#include"../source/server.hpp"
#include<fstream>
#include<regex>
#include <sstream>
#include <ctype.h>
#define DEFAULT_TIMEOUT 10

unordered_map<int,string> statu_info = {
        {100,  "Continue"},
        {101,  "Switching Protocol"},
        {102,  "Processing"},
        {103,  "Early Hints"},
        {200,  "OK"},
        {201,  "Created"},
        {202,  "Accepted"},
        {203,  "Non-Authoritative Information"},
        {204,  "No Content"},
        {205,  "Reset Content"},
        {206,  "Partial Content"},
        {207,  "Multi-Status"},
        {208,  "Already Reported"},
        {226,  "IM Used"},
        {300,  "Multiple Choice"},
        {301,  "Moved Permanently"},
        {302,  "Found"},
        {303,  "See Other"},
        {304,  "Not Modified"},
        {305,  "Use Proxy"},
        {306,  "unused"},
        {307,  "Temporary Redirect"},
        {308,  "Permanent Redirect"},
        {400,  "Bad Request"},
        {401,  "Unauthorized"},
        {402,  "Payment Required"},
        {403,  "Forbidden"},
        {404,  "Not Found"},
        {405,  "Method Not Allowed"},
        {406,  "Not Acceptable"},
        {407,  "Proxy Authentication Required"},
        {408,  "Request Timeout"},
        {409,  "Conflict"},
        {410,  "Gone"},
        {411,  "Length Required"},
        {412,  "Precondition Failed"},
        {413,  "Payload Too Large"},
        {414,  "URI Too Long"},
        {415,  "Unsupported Media Type"},
        {416,  "Range Not Satisfiable"},
        {417,  "Expectation Failed"},
        {418,  "I'm a teapot"},
        {421,  "Misdirected Request"},
        {422,  "Unprocessable Entity"},
        {423,  "Locked"},
        {424,  "Failed Dependency"},
        {425,  "Too Early"},
        {426,  "Upgrade Required"},
        {428,  "Precondition Required"},
        {429,  "Too Many Requests"},
        {431,  "Request Header Fields Too Large"},
        {451,  "Unavailable For Legal Reasons"},
        {501,  "Not Implemented"},
        {502,  "Bad Gateway"},
        {503,  "Service Unavailable"},
        {504,  "Gateway Timeout"},
        {505,  "HTTP Version Not Supported"},
        {506,  "Variant Also Negotiates"},
        {507,  "Insufficient Storage"},
        {508,  "Loop Detected"},
        {510,  "Not Extended"},
        {511,  "Network Authentication Required"}
};

unordered_map<string,string> file_mime = {
        {".aac",        "audio/aac"},
        {".abw",        "application/x-abiword"},
        {".arc",        "application/x-freearc"},
        {".avi",        "video/x-msvideo"},
        {".azw",        "application/vnd.amazon.ebook"},
        {".bin",        "application/octet-stream"},
        {".bmp",        "image/bmp"},
        {".bz",         "application/x-bzip"},
        {".bz2",        "application/x-bzip2"},
        {".csh",        "application/x-csh"},
        {".css",        "text/css"},
        {".csv",        "text/csv"},
        {".doc",        "application/msword"},
        {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".eot",        "application/vnd.ms-fontobject"},
        {".epub",       "application/epub+zip"},
        {".gif",        "image/gif"},
        {".htm",        "text/html"},
        {".html",       "text/html"},
        {".ico",        "image/vnd.microsoft.icon"},
        {".ics",        "text/calendar"},
        {".jar",        "application/java-archive"},
        {".jpeg",       "image/jpeg"},
        {".jpg",        "image/jpeg"},
        {".js",         "text/javascript"},
        {".json",       "application/json"},
        {".jsonld",     "application/ld+json"},
        {".mid",        "audio/midi"},
        {".midi",       "audio/x-midi"},
        {".mjs",        "text/javascript"},
        {".mp3",        "audio/mpeg"},
        {".mpeg",       "video/mpeg"},
        {".mpkg",       "application/vnd.apple.installer+xml"},
        {".odp",        "application/vnd.oasis.opendocument.presentation"},
        {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
        {".odt",        "application/vnd.oasis.opendocument.text"},
        {".oga",        "audio/ogg"},
        {".ogv",        "video/ogg"},
        {".ogx",        "application/ogg"},
        {".otf",        "font/otf"},
        {".png",        "image/png"},
        {".pdf",        "application/pdf"},
        {".ppt",        "application/vnd.ms-powerpoint"},
        {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        {".rar",        "application/x-rar-compressed"},
        {".rtf",        "application/rtf"},
        {".sh",         "application/x-sh"},
        {".svg",        "image/svg+xml"},
        {".swf",        "application/x-shockwave-flash"},
        {".tar",        "application/x-tar"},
        {".tif",        "image/tiff"},
        {".tiff",       "image/tiff"},
        {".ttf",        "font/ttf"},
        {".txt",        "text/plain"},
        {".vsd",        "application/vnd.visio"},
        {".wav",        "audio/wav"},
        {".weba",       "audio/webm"},
        {".webm",       "video/webm"},
        {".webp",       "image/webp"},
        {".woff",       "font/woff"},
        {".woff2",      "font/woff2"},
        {".xhtml",      "application/xhtml+xml"},
        {".xls",        "application/vnd.ms-excel"},
        {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".xml",        "application/xml"},
        {".xul",        "application/vnd.mozilla.xul+xml"},
        {".zip",        "application/zip"},
        {".3gp",        "video/3gpp"},
        {".3g2",        "video/3gpp2"},
        {".7z",         "application/x-7z-compressed"}
};

class Util
{
public:
  //字符串分割函数 abc,ada,
  static size_t Split(const string& src,const string& sep,vector<string>* array)
  {
      size_t offset = 0;//
      while(offset < src.size())
      {
          size_t pos = src.find(sep,offset); //从src的offset位置开始找sep
          //没找到分隔符：将剩余部分存到数组
          if(pos == std::string::npos)
          {
              array->push_back(src.substr(offset));
              return array->size();
          }
          //abd,,efg对于连续两个分割符不用提取但是注意要跳过分割符
          if(pos == offset)
          {
             offset = pos + sep.size(); //别忘了更新offset
             continue;
          }
          //正常情况
          array->push_back(src.substr(offset,pos-offset));
          offset = pos + sep.size(); //别忘了更新offset
      }
      return array->size();
  }
  //读取文件内容
  static bool ReadFile(const string& filename,string* result)
  {
    //1.定义流对象打开文件
    ifstream ifs(filename,std::ios::binary);
    if(!ifs.is_open())
    {
        ERR_LOG("open %s file failed!!",filename.c_str());
        perror("Error");  // 打印系统的错误信息
        ifs.close();
        return false;
    }
    //2.获取文件大小并读取文件(注意使用流提取，遇到换行符会停止)
    string line;
    while (getline(ifs, line)) 
    {
       *result += line;
       *result += "\n";
    }
    // 3. 判断是否读取完文件
    if (ifs.eof())  // 如果是正常的文件结束
    {
        return true;  // 文件读取成功
    }
    // 如果不是因为文件结束而导致读取失败
    ERR_LOG("read %s file failed!!", filename.c_str());
    return false;
  }
  //向文件写入数据
  static bool WriteFile(const string& filename,const string& data)
  {
        //1.打开文件
        ofstream ofs(filename,std::ios::binary|std::ios::trunc); 
        if(!ofs.is_open())
        {
            DBG_LOG("open %s file failed!!",filename.c_str());
            ofs.close();
            return false;
        }
        //2.写文件
        std::cout << "data: " << data << std::endl;
        ofs << data;
        //3.判断
        if(ofs.good() == false)
        {
            DBG_LOG("write %s file failed!!",filename.c_str());
            ofs.close();
            return false;
        }
        DBG_LOG("Write OK");
        return true;
  }
 //URL编码
  static string UrlEnCode(const string& url,bool is_spaceto_plus)
  {
       string result;
       for(const auto& ch : url)
       {
           //不需要编码
           if(ch == '.' || ch == '-' || ch == '_' || ch == '~' || isalnum(ch))
           {
                result += ch;
                continue;
           }
           //遇到空格
           if(ch == ' ' && is_spaceto_plus)
           {
              result += '+';
              continue;
           }
           //剩下的是需要编码为%HH
           char temp[4];
           snprintf(temp,4,"%%%02X",ch);
           result += temp;
       } 
       return result;
  }

  static char HEXTOB(char c)
  {
      //数字
      if(c >= '0' && c <= '9')
       return c - '0';
      //小写字符
      if(c >= 'a' && c <= 'z')
        return c - 'a' + 10; //注意这里要加10
      if(c >= 'A' && c <= 'Z')
        return c - 'A' + 10;
  }

  static string UrlDeCode(const string& url,bool is_spaceto_plus)
  {
     string result;
     for(int i = 0 ; i < url.size() ; i++)
     {
        char ch = url[i];
        if(ch == '+' && is_spaceto_plus)
        {
              result += ' ';
              continue;
        }
        //遇到%
        if(ch == '%' && i+2 < url.size())
        {
            // cout << (char)url[i+1] << " " << (char)url[i+2] << " " ;
            char ch1 = HEXTOB(url[i+1]);
            char ch2 = HEXTOB(url[i+2]);
            char temp = ch1 * 16 +  ch2;
            // cout << (char)temp << endl;  
            result += (char)temp; //注意这里要强转成char
            i += 2; //注意这里要跳过两个字符
            continue;
        }
        //不需要编码
        result += ch;
     }
     return result;
  }

  //响应状态码的描述信息获取
  static string StatuDesc(int statu_code)
  {
     auto it = statu_info.find(statu_code);
     if(it == statu_info.end())
       return "NotKown Statu";
     return it->second; 
  }
  
  //根据文件后缀名获取文件mime
  static string ExtMime(const string& filename)
  {
      //1.先根据文件名获取文件后缀
      size_t pos = filename.find_last_of('.');
      if(pos == string::npos)
          return "No Suffix";
       string Suffix = filename.substr(pos); 
      //2.哈希表中查找
      auto it = file_mime.find(Suffix);
      if(it == file_mime.end())
       return "NotKown Mime";
      return it->second; 

  }

  //判断一个文件是否是一个目录
  static bool isDirectory(const string& filename )
  {
    //1.获取文件属性
    struct stat st;
    int n = ::stat(filename.c_str(),&st);
    if(n < 0) return false;
    //2.s_mode
    return S_ISDIR(st.st_mode);
  }

  //判断一个文件是否是一个普通文件
  static bool isRegular(const string& filename )
  {
    //1.获取文件属性
    struct stat st;
    int n = ::stat(filename.c_str(),&st);
    if(n < 0) return false;
    //2.s_mode
    return S_ISREG(st.st_mode);
  }
  //http请求的资源路径有效性判断
  static bool ValidPath(const string& path)
  {
      int level = 0 ;
      //1.字符串切分
      vector<string> array;
      Split(path,"/",&array);
      //2.计算深度
      for(auto& s : array)
      {
         if(s == "..")
         {
            level--;
            if(level < 0) return false;///任意一层走出相对根目录,就认为有问题
            continue;
         }
         level++;
      }
      return true;
  }

};

class HttpRequest
{
public:
   string _method; //请求方法
   string _path; //资源路径
   string _version;//协议版本
   string _body;   //请求正文
   std::smatch _matches; //资源路径的正则提取
   unordered_map<string,string> _headers;//头部字段
   unordered_map<string,string> _params; //查询字符串
public:
   void SetHeader(string& key,string& val)   //插入头部字段
   {
      _headers[key] = val;
   }
   bool HasHeader(string key) const //是否存在指定头部字段
   {
      auto it = _headers.find(key);
      if(it == _headers.end()) return false;
      return true;
   }
   string GetHeader(string key)const //获取指定头部字段的值
   {
       auto it = _headers.find(key);
       if(it == _headers.end()) return "None";
       return it->second;
   }
   void SetParams(string& key,string&val)//插入查询字符串
   {
       _params[key] = val;
   }
   bool HasParam(string& key)  //判断是否存在指定的查询字符串
   {
      auto it = _params.find(key);
      if(it == _params.end()) return false;
      return true;
   }
   string GetParam(string&key) //获取指定的查询字符串
   {
      auto it = _params.find(key);
      if(it == _params.end()) return "None";
      return it->second;
   }
   size_t ContentLength() //获取正文长度
   {
       auto it = _headers.find("Content-Length");
       if(it == _headers.end()) return 0;
       return stol(it->second);
   }
   bool Close()const //判断是否是长连接
   {
      //没有Connection字段或有Connetion字段但是是Close的都是短连接
      if(HasHeader("Connection") && GetHeader("Connection") == "keep-alive")
        return true;
      return false;
   }

   HttpRequest()
   :_version("HTTP/1.1")
   {}

   void Reset()  //每次上下文请求被处理完需要重置一下，否则可能会对下次请求造成干扰
   {
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _body.clear();
        std::smatch matches;
        _matches.swap(matches);
        _headers.clear();
        _params.clear();
   }
};


class HttpResponse
{
public:
   int _status; //状态码
   string _body; //正文
   bool _is_redirect; //表示是否重定向
   string _redir_url;
   unordered_map<string,string> _headers;//头部字段
public: 
    HttpResponse()
    :_status(200),_is_redirect(false)
    {}

    HttpResponse(int statu)
    :_status(statu),_is_redirect(false)
    {}

   void Reset() //重置上下文
   {
      _status = 200;
      _is_redirect = false;
      _redir_url.clear();
      _body.clear();
      _headers.clear();
   }

   void SetHeader(string key,string val) //设置正文
   {
       _headers[key] = val;
   }

   bool HasHeader(string key) //是否存在指定头部字段
   {
      auto it = _headers.find(key);
      if(it == _headers.end()) return false;
      return true;
   }
   string GetHeader(string key) //获取指定头部字段的值
   {
       auto it = _headers.find(key);
       if(it == _headers.end()) return "None";
       return it->second;
   }
   void SetContent(string body,string type) //设置正文的同时把Content-type也设置了
   {
         _body = body;
         SetHeader("Content-type",type);
   }

   bool Close()//判断是否是长链接
   {
      //没有Connection字段或有Connetion字段但是是Close的都是短连接
      if(HasHeader("Connection") && GetHeader("Connection") == "keep-alive")
        return true;
      return false;
   }

   bool SetRedircet(string& url,int statu = 302) //设置重定向
   {
      _is_redirect = true;
      _redir_url = url;
      _status = statu;
   }
};

typedef enum {
   RECV_HTTP_ERROR, //解析失败
   RECV_HTTP_LINE,  //解析请求行
   RECV_HTTP_HEAD,  //解析头部
   RECV_HTTP_BODY,  //解析正文
   RECV_HTTP_OVER   //解析结束
}HttpRecvStatus;

#define MAX_LINE 8192 //8KB一行最大数据

//上下文
class HttpContext
{
private:
   int _resp_statu; //响应状态码
   HttpRecvStatus _recv_statu; //当前接收及解析的阶段状态
   HttpRequest _request; //已经解析得到的请求信息
public:
   void Reset()
   {
      _resp_statu = 200;
      _recv_statu = RECV_HTTP_LINE;
      _request.Reset();
   }

   bool RecvHttpLine(Buffer* buf)
   {
      if(_recv_statu != RECV_HTTP_LINE) return false;
      //1.从缓冲区中读取数据
      string line = buf->GetLineAndPop();
      //读取数据不足一行（GetLineAndPop会返回空串）
      if(line.size() == 0)
      {
         //1.1缓冲区数据不足一行且缓冲区中的可读数据很长
         if(buf->ReadAbleSize() > MAX_LINE)
         {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 414; //URI TOO LONG
            return false;
         }
         //1.2不足一行但是没超过MAX_LINE : 等待新数据到来
         return true;
      }
      //1.3读取数据有一行,但是超过MAX_LINE
      if(line.size() > MAX_LINE)
      {
           _recv_statu = RECV_HTTP_ERROR;
           _resp_statu = 414; //URI TOO LONG
           DBG_LOG("414 error");
           return false;
      }
      //2.读取数据出一行且在正常范围,则进行解析
      bool ret = ParseHttpLine(line);
      if(ret == false) return false;
      //更新状态
      _recv_statu = RECV_HTTP_HEAD;
      // DBG_LOG("ParseLine Success");
      return true;
   }

   bool ParseHttpLine(string& line)
   {
      //1.使用正则库解析请求行
      std::smatch matches;
      std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?",std::regex::icase);
      bool ret = std::regex_match(line,matches,e);
      if(ret == false)
      {
          _recv_statu = RECV_HTTP_ERROR;
          _resp_statu = 400; //BAD REQUEST
          DBG_LOG("BAD REQUEST");
          return false;
      }
      //0 : GET /bitejiuyeke/login?user=xiaoming&pass=123123  HTTP/1.1
      //1:  GET
      //2:  /bitejiuyeke/login
      //3 : user=xiaoming&pass=123123
      //4:  HTTP/1.1

      //2.保存关键要素
      //2.1
      _request._method = matches[1];
      std::transform(_request._method.begin(),_request._method.end(),_request._method.begin(),::toupper);
      _request._path = Util::UrlDeCode(matches[2],false);
      _request._version = matches[4];
      // DBG_LOG("%s %s %s",_request._method.c_str(),_request._path.c_str(),_request._version.c_str());
      //2.2查询字符串要素 以&分割查询字符串然后设置到HttpRequest的_params中
      vector<string> query_array;
      Util::Split(matches[3],"&",&query_array);
      for(const auto& query : query_array)
      {
         //按照=进行分隔
         size_t  pos = query.find("=");
         if(pos == string::npos)
         {
             _recv_statu = RECV_HTTP_ERROR;
             _resp_statu = 400; //BAD REQUEST
             DBG_LOG("BAD REQUEST");
             return false;
         }
         //注意要进行解码
         string key = Util::UrlDeCode(query.substr(0,pos),true);
         string val = Util::UrlDeCode(query.substr(pos+1),true);
         _request.SetParams(key,val);
      }
      return true;
   }

   bool RecvHttpHead(Buffer* buf)
   {
         if(_recv_statu != RECV_HTTP_HEAD) return false;
         while(buf->ReadAbleSize() > 0) //有数据就读
         {
              //1.从缓冲区中读取数据
               string line = buf->GetLineAndPop();
               //读取数据不足一行（GetLineAndPop会返回空串）
               if(line.size() == 0)
               {
                  //1.1缓冲区数据不足一行且缓冲区中的可读数据很长
                  if(buf->ReadAbleSize() > MAX_LINE)
                  {
                     _recv_statu = RECV_HTTP_ERROR;
                     _resp_statu = 414; //URI TOO LONG
                     return false;
                  }
                  //1.2不足一行但是没超过MAX_LINE : 等待新数据到来
                  return true;
               }
               //1.3读取数据有一行,但是超过MAX_LINE
               if(line.size() > MAX_LINE)
               {
                  _recv_statu = RECV_HTTP_ERROR;
                  _resp_statu = 414; //URI TOO LONG
                  return false;
               }
               //2.正常读取到一行数据， 读取到空行结束
               if(line == "\n" || line == "\r\n")
                 break;
               //3.解析头部
               bool ret = ParseHttpHead(line);
               if(ret == false) return false;
         }
       _recv_statu = RECV_HTTP_BODY;
      // DBG_LOG("ParseHead Success");
       return true;
   }

   bool ParseHttpHead(string& line)
   {
         if(line.back() == '\n') line.pop_back();
         if(line.back() == '\r') line.pop_back();
         size_t pos = line.find(":");
         if(pos == string::npos)
         {
             _recv_statu = RECV_HTTP_ERROR;
             _resp_statu = 400; //BAD REQUEST
             DBG_LOG("BAD REQUEST");
             return false;
         }
         //注意要进行解码
         string key = line.substr(0,pos);
         string val = line.substr(pos+1);
         _request.SetHeader(key,val);
        return true;
   }

   bool RecvHttpBody(Buffer* buf)
   {
      if(_recv_statu != RECV_HTTP_BODY) return false;
       //1.获取正文长度
      size_t content_len = _request.ContentLength();
      //2.正文长度为0，则解析完毕
      if(content_len == 0)
      {
          _recv_statu = RECV_HTTP_OVER;
          return true;
      }
      //3.正文长度不为0 计算还需要接收的正文长度
      size_t need_len = content_len - _request._body.size();
      //4.接收正文到body中
      //4.1 缓冲区中数据包含当前请求所需正文
      if(buf->ReadAbleSize() >= need_len)
      {
         _request._body.append(buf->ReadPos(),need_len);
         buf->MoveReadIdx(need_len);
         _recv_statu = RECV_HTTP_OVER;
         return true;
      }
      //4.2 缓冲区数据不满足要求，等待新数据（bug:这里是读取ReadAbleSize）
      _request._body.append(buf->ReadPos(),buf->ReadAbleSize());
      buf->MoveReadIdx(buf->ReadAbleSize());
      return true;
   }

public:
   HttpContext()
   :_resp_statu(200),_recv_statu(RECV_HTTP_LINE)
   {}
   int RespStatu() //获取响应状态码
   {
      return _resp_statu;
   }
   HttpRecvStatus RecvStatu() //获取当前接收及解析状态
   {
      return _recv_statu;
   }
   HttpRequest& Request() //获取解析好的请求
   {
      return _request;
   }
   void RecvHttpRequest(Buffer* buf) //接收并解析HTTP请求
   {
      //这里不要break 当接收处理完请求行应该立即接收头部
      switch(_recv_statu)
      {
         case RECV_HTTP_LINE: RecvHttpLine(buf);
         case RECV_HTTP_HEAD: RecvHttpHead(buf);
         case RECV_HTTP_BODY: RecvHttpBody(buf);
      }
      return;
   }
};


class HttpServer
{
private:
   using Handler = std::function<void(const HttpRequest&,HttpResponse*)>;
   using Handlers = std::vector<pair<std::regex,Handler>>;
   //由于每一次请求我们都需要将正则表达式进行编译来构造正则表达式对象,这样是比较慢的,我们可以直接记录映射正则和处理方法的映射
   //将key修改为regex对象,即正则表达式对象
   //路由表
   Handlers _get_route;
   Handlers _post_route;
   Handlers _put_route;
   Handlers _delete_route;
   string _basedir; //静态资源根目录
   TcpServer _server;
private:
    void WriteResponse(const PtrConnection& conn,const HttpRequest& req, HttpResponse& rsp) //将HttpRespnse中的要素按照http协议格式进行组织发送
    {
       //1.完善rsp中的头部字段
       //1.1短/长链接
       if(req.Close()) rsp.SetHeader("Connection","keep-alive");
       else rsp.SetHeader("Connection","close");
       //1.2Content-Length:看正文是不是不为空&&没被设置
       if(!rsp._body.empty() && !rsp.HasHeader("Content-Length"))
            rsp.SetHeader("Content-Length",to_string(rsp._body.size()));
        //1.3Content-Type: 看正文是不是不为空 && Content-Type没被设置(默认设置为application/octet-stream)
       if(!rsp._body.empty() && !rsp.HasHeader("Content-Type"))
            rsp.SetHeader("Content-Type","application/octet-stream");
       //1.4 Location：是否允许重定向&& location没被设置
       if(rsp._is_redirect)
            rsp.SetHeader("Location",rsp._redir_url);
       //2. 将rsp中的要素按照HTTP协议格式组织起来
       stringstream ss;
       ss << req._version << " " <<  to_string(rsp._status) << " " << Util::StatuDesc(rsp._status) << "\r\n";
       for(auto& pr : rsp._headers )
           ss << pr.first << ":" << pr.second << "\r\n";
       ss << "\r\n";
       ss << rsp._body;  
       //3.发送响应
       conn->Send(ss.str().c_str(),ss.str().size());
    }

    bool isFileHandler(const HttpRequest& req)//判断是否是静态资源请求
    {
       //1.必须设置了静态资源目录
       if(_basedir.empty())
       {
          DBG_LOG("basedir empty");
          return false;
       }
       //2.请求方法必须是GET或HEAD（注意这里判断条件是req._method != "GET" && req._method != "HEAD"）
      //  if(req._method != "GET" || req._method != "HEAD")
      //  {
      //     DBG_LOG("method Error,%s",req._method.c_str());
      //     return false;
      //  }
       if(req._method != "GET" && req._method != "HEAD")
       {
          DBG_LOG("method Error,%s",req._method.c_str());
          return false;
       }
       //3.请求的资源路径必须是一个合法路径
       if(!Util::ValidPath(req._path))
       {
           DBG_LOG("Not a ValidPath");
           return false;
       }
       //4.请求的资源必须存在且是一个普通文件(注意/的情况在后面追加上index.html)
       string req_path = _basedir + req._path; //为了避免直接修改请求的资源路径,因此定义一个临时对象象
      //  DBG_LOG("%s",req_path.c_str());
       if(req_path.back() == '/')
         req_path += "index.html";
       if(!Util::isRegular(req_path)) return false;
       return true; 
    }

    bool FileHandler(const HttpRequest& req,HttpResponse* rsp )//静态资源的处理
    {
          string req_path = _basedir + req._path;
         //  DBG_LOG("%s",req_path.c_str());
          if(req_path.back() == '/')
            req_path += "index.html";
          //1.读取文件数据到body中
          bool ret = Util::ReadFile(req_path,&rsp->_body);
          if(ret == false) return false;
          //2.设置mime
          string mime = Util::ExtMime(req_path);
          rsp->SetHeader("Content-Type",mime);
          return true;
    } 

    void Dispatcher( HttpRequest& req,HttpResponse* rsp,Handlers& handlers)//功能性请求的分类处理
    {
        for(auto& handler : handlers)
        {
           regex& re = handler.first;
           Handler& func = handler.second;
           bool ret = std::regex_match(req._path,req._matches,re); //注意这里修改了req._matches不能使用const对象
           if(ret == false) continue;
           return func(req,rsp);//传入请求信息和空的rsp
        }
        //没有就报错
        rsp->_status = 404;
    }

    void Route(HttpRequest& req,HttpResponse* rsp) //路由 
    {
         //1.是静态资源请求则进行静态资源处理
         if(isFileHandler(req))
         {
            FileHandler(req,rsp);
            return;
         }   
         // DBG_LOG("功能性请求...");
         // DBG_LOG("%s",req._method.c_str());
         // DBG_LOG("%s",req._path.c_str());
         //2.功能性请求：看是否能在路由表找到
         if(req._method == "GET" || req._method == "HEAD")
             return Dispatcher(req,rsp,_get_route);
         else if(req._method == "POST")   
              return Dispatcher(req,rsp,_post_route); 
         else if(req._method == "PUT")
              return Dispatcher(req,rsp,_put_route); 
          else if(req._method == "DELETE")
              return Dispatcher(req,rsp,_delete_route);
         //3.不是静态或是功能性但是没有找到对应路由,报错405
          rsp->_status = 405; //Method Not Allowed
          DBG_LOG("405 ERROR");
    }

    void ErrorHandler(const HttpRequest& req,HttpResponse* rsp)//解析出错调用
    {
      //1.组织错误回复
      string body;
      body += "<!DOCTYPE html>";
      body += "<html kang='en'>";
      body += "<head>";
      body += "<meta charset='UTF-8'>";
      body += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
      body += "<title>Error</title>";
      body += "</head>";
      body += "<body>";
      body += "<h1>" + to_string(rsp->_status) + Util::StatuDesc(rsp->_status) + "</h1>";
      body += "</body>";
      body += "</html>";
      //2.设置到rsp的body中
      rsp->SetContent(body,"text/html");
    }
    void OnConnection(const PtrConnection& conn) //为连接设置上下文
    {
       conn->SetContext(HttpContext());
       DBG_LOG("NEW CONNECTION:%p",conn.get());
    }

    void OnMessage(const PtrConnection& conn,Buffer* buffer) //缓冲区数据解析+处理
    {
         string content = buffer->ReadAsString(buffer->ReadAbleSize());
         // DBG_LOG("%s",content.c_str());
         while(buffer->ReadAbleSize() > 0)
         {
            //1.获取连接对应的上下文
            HttpContext* context = conn->GetContext()->get<HttpContext>();
            //2.通过上下文对缓冲区数据进行解析,得到HttpRequest对象
            context->RecvHttpRequest(buffer);
            //2.1缓冲区数据解析出错,直接回复出错响应,关闭连接
            HttpRequest& req = context->Request();
            HttpResponse rsp(context->RespStatu());
            if(context->RespStatu()>=400) //进行错误响应关闭连接
            {
                  // DBG_LOG("%s",buffer->ReadAsString(buffer->ReadAbleSize()).c_str());
                  DBG_LOG("parse error");
                  ErrorHandler(req,&rsp);//填充一个错误显示页面数据到rsp中
                  WriteResponse(conn,req,rsp); //组织响应发送
                  //bug：这里需要重置上下文尤其是recv_status，因为关闭连接之前我们会查看缓冲区
                  //     中是否还有数据，此时又会调用onMessage，但是状态还是error就不能取出缓冲区中数据
                  //     到这里的时候，又调用conn->ShutDown()发现缓冲区中还有数据，又调用onMessage陷入死循环
                  context->Reset();
                  buffer->MoveReadIdx(buffer->ReadAbleSize());
                  conn->ShutDown();//关闭连接
                  return;
            }
            //2.2解析正常:可能请求没有获取完整/请求已经获取完毕进行处理
            if(context->RecvStatu() != RECV_HTTP_OVER)
               return;
            //3.请求路由+业务处理
            Route(req,&rsp);
            //4.对HttpRespnse进行组织发送
            WriteResponse(conn,req,rsp);
            // DBG_LOG("缓冲区数据:%d",buffer->ReadAbleSize());
            //5.请求处理完成,重置连接的上下文,防止影响到下一请求
            context->Reset();
            //6.判断长短连接:长连接则缓冲区有数据就循环处理,短连接则断开连接
            if(rsp.Close() == false)
            {
                DBG_LOG("关闭短链接");
               conn->ShutDown();
            }  
         }
    }

 public:  
    HttpServer(int port,int timeout = DEFAULT_TIMEOUT)
    :_server(port)
    {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallBack(std::bind(&HttpServer::OnConnection,this,std::placeholders::_1));
        _server.SetMessageCallBack(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
    }
    void SetBaseDir(const string& dir) //设置静态资源根目录
    {
        bool ret = Util::isDirectory(dir);
        assert(ret == true);
        _basedir = dir; 
    }
    void Get(const string& pattern,const Handler& handler)
    {
       _get_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Post(const string& pattern,const Handler& handler)
    {
        _post_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Put(const string& pattern,const Handler& handler)
    {
        _put_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Delete(const string& pattern,const Handler& handler)
    {
        _delete_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void SetThreadCount(int count) //设置服务器中线程池中数量
    {
        _server.SetThreadCount(count);
    }
    void EnableInactiveRelease(int timeout) //启动非活跃超时连接销毁
    {
        _server.EnableInactiveRelease(timeout);
    }
    void Listen() //启动服务器
    {
       _server.Start();
    }
};
